﻿//=====================================================================================================
// LocalizationLibrary
// The Localization Library is a collection of reusable software component that provide 
// support for localization. This library enable you to localize WPF, Silverlight and WP7 applications.
// (http://localizationlibrary.codeplex.com)
//=====================================================================================================
// Author: Nicola Gallo (Website: www.nicola.gallo.name, Email: nicolagmt@hotmail.it) 
//=====================================================================================================

namespace LocalizationLibrary.Reflection
{
    //.NET References
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Resources;

    /// <summary>
    /// Represents a xap deployment part.
    /// </summary>
    public class XapDeploymentPart : DeploymentPart
    {
        //Fields

        /// <summary>
        /// Gets loaded assemblies.
        /// </summary>
        private Dictionary<String, Assembly> _assemblies;

        //Constructors

        /// <summary>
        /// Creates a new instanec of <see cref="XapDeploymentPart"/>.
        /// </summary>
        /// <param name="uri">DeploymentPart's uri.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown whether <paramref name="deploymentPartKind"/> parameter is null.
        /// </exception>
        public XapDeploymentPart(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("deploymentPartUri parameter shouldn't be null.");
            }
            this.Uri = uri;
            this.DeploymentPartKind = DeploymentPartKind.Xap;
        }

        //Properties

        /// <summary>
        /// Gets true if the deployment part is loaded, false otherwise.
        /// </summary>
        public bool IsLoaded { get; private set; }

        /// <summary>
        /// Gets loaded assemblies.
        /// </summary>
        protected Dictionary<String, Assembly> Assemblies
        {
            get
            {
                if (this._assemblies == null)
                {
                    this._assemblies = new Dictionary<string, Assembly>();
                }
                return this._assemblies;
            }
        }

        /// <summary>
        /// Gets the <see cref="XapDeploymentPart"/>'s uri.
        /// </summary>
        public Uri Uri { get; private set; }

        /// <summary>
        /// Gets the <see cref="XapDeploymentPart"/>'s kind.
        /// </summary>
        public DeploymentPartKind DeploymentPartKind { get; private set; }

        //Methods

        /// <summary>
        /// Load the input <paramref name="DeploymentPartAsyncResult"/> parameter.
        /// </summary>
        /// <param name="deploymetPartAsyncResult">Represents the status of an asynchronous <see cref="XapDeploymentPart"/> loading operation.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown whether <paramref name="deploymetPartAsyncResult"/> parameter is not a <see cref="XapDeploymetPartAsyncResult"/> instance.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown whether the deployment part has been already loaded.
        /// </exception>
        public override void Load(DeploymetPartAsyncResult deploymetPartAsyncResult) 
        {
            XapDeploymetPartAsyncResult xapDeploymetPartAsyncResult = deploymetPartAsyncResult as XapDeploymetPartAsyncResult;
            if (xapDeploymetPartAsyncResult == null)
            {
                throw new ArgumentNullException("deploymetPartAsyncResult shouldn't be null.");
            }
            if (this.IsLoaded)
            {
                throw new InvalidOperationException("DeploymentPart has been already loaded.");
            }
            this.IsLoaded = true;
            foreach (var assemblyPart in xapDeploymetPartAsyncResult.AssemblyParts)
            {
                StreamResourceInfo streamResInfo = xapDeploymetPartAsyncResult.StreamResourceInfo;
                StreamResourceInfo assemblySri = Application.GetResourceStream(streamResInfo, new Uri(assemblyPart.Source, UriKind.Relative));
                Assembly assembly = new AssemblyPart().Load(assemblySri.Stream);
                if ((assembly != null) && (!this.Assemblies.ContainsKey(assembly.FullName)))
                {
                    this.Assemblies.Add(assembly.FullName, assembly);
                    this.PublishAssembly(assembly);
                }     
            }
        }

        /// <summary>
        /// Gets all loaded assemblies.
        /// </summary>
        /// <returns>Loaded assemblies.</returns>
        public override Assembly[] GetAssemblies()
        {
            return this.Assemblies.Values.ToArray();
        }

        /// <summary>
        /// Serves as a hash function for <see cref="XapDeploymentPart"/> type.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Uri.ToString().GetHashCode();
        }

        /// <summary>
        /// Determines whether the specified <see cref="XapDeploymentPart"/>
        /// is equal to the current <see cref="XapDeploymentPart"/>.
        /// </summary>
        /// <param name="obj">Instance.</param>
        /// <returns>True if the input instance is equals to the current instance.</returns>
        public override bool Equals(object obj)
        {
            if (this == obj)
            {
                return true;
            }
            else if ((obj == null) || (obj.GetType() != this.GetType()))
            {
                return false;
            }
            XapDeploymentPart deploymentPart = obj as XapDeploymentPart;
            return deploymentPart.Uri.ToString().Equals(this.Uri.ToString());
        }
    }
}
